import { Router } from "express";
import Fs from "fs-extra";
import Path from "path";
import { createServer as createViteDevServer } from "vite";
import { vueWebPath } from "./vite-config";
import { vueProdServer } from "./vue-production-server";

/** (Promise) viteServer, 可以用于router.use */
export const viteServer = createViteDevServer({
  server: { middlewareMode: "html" },
});

/**
 * 利用vite创建默认的vue-dev-server
 * @param htmlPath html文件路径
 * @example import { vueServer } from "albert.gao/default/vue-production-server"
 * @returns Promise<Router>
 */
export async function vueDevServer(
  htmlPath: string = Path.resolve(vueWebPath, "index.html")
): Promise<Router> {
  const router = Router();
  let _server = await viteServer;
  router.use(_server.middlewares);
  router.use("*", async (req, res) => {
    const { originalUrl: url } = req;
    try {
      // 1. 读取 index.html
      let template = Fs.readFileSync(htmlPath, "utf-8");
      // 2. 应用 Vite HTML 转换。这将会注入 Vite HMR 客户端，
      //    同时也会从 Vite 插件应用 HTML 转换。
      //    例如：@vitejs/plugin-react 中的 global preambles
      template = await _server.transformIndexHtml(url, template);
      // // 3. 加载服务器入口。vite.ssrLoadModule 将自动转换
      // //    你的 ESM 源码使之可以在 Node.js 中运行！无需打包
      // //    并提供类似 HMR 的根据情况随时失效。
      // const { render } = await viteServer.ssrLoadModule('/entry-server.js')
      // console.log(render)
      // // 4. 渲染应用的 HTML。这假设 entry-server.js 导出的 `render`
      // //    函数调用了适当的 SSR 框架 API。
      // //    例如 ReactDOMServer.renderToString()
      // const appHtml = await render(url)
      // console.log(appHtml)

      // 6. 返回渲染后的 HTML。
      res.status(200).set({ "Content-Type": "text/html" }).end(template);
    } catch (e) {
      // 如果捕获到了一个错误，让 Vite 来修复该堆栈，这样它就可以映射回
      // 你的实际源码中。
      // console.error(e);
      _server.ssrFixStacktrace(e as Error);
      res.status(500).end((e as Error).message);
    }
  });
  return router;
}

/**
 * @deprecated
 * @param isProd 在electron下无需填写，但在nodejs中需要填写
 * @example import { vueServer } from "albert.gao/default/vue-production-server"
 * @returns ExpressRouter
 */
export async function vueServer(
  /**
   * 是否为生产模式
   */
  isProd: boolean = require("electron").app.isPackaged
): Promise<Router> {
  return isProd ? vueProdServer() : await vueDevServer();
}
